<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8">
  <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport">
  <meta name="baidu-site-verification" content="code-UjJKh3jtOo">
  <link rel="stylesheet" href="//unpkg.com/@highlightjs/cdn-assets@11.5.0/styles/atom-one-dark.min.css">
  <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
  <title>Tit1e</title>
  <script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-2767111597631391" crossorigin="anonymous"></script>
  
<link rel="stylesheet" href="/css/style.css">

<meta name="generator" content="Hexo 6.3.0"><link rel="alternate" href="/atom.xml" title="Tit1e" type="application/atom+xml">
</head>

<body class="dark">
    <div class="container">
    <header class="header">
  <div class="title">
      <a href="/" class="logo">Tit1e</a>
      <div class="btn-dark"></div>
      <script>
        let bodyClx = document.body.classList;
        let btnDark = document.querySelector('.btn-dark');
        let sysDark = window.matchMedia('(prefers-color-scheme: dark)');
        let darkVal = localStorage.getItem('dark');

        let setDark = (isDark) => {
        bodyClx[isDark ? 'add' : 'remove']('dark');
        localStorage.setItem('dark', isDark ? 'yes' : 'no');
        };

        setDark(darkVal ? darkVal === 'yes' : sysDark.matches);
        requestAnimationFrame(() => bodyClx.remove('not-ready'));

        btnDark.addEventListener('click', () => setDark(!bodyClx.contains('dark')));
        sysDark.addEventListener('change', (event) => setDark(event.matches));
      </script>
  </div>
    <ul class="menu">
        
        
        
        
        <li class="menu-item ">
            <a href="/" class="menu-item-link">Home</a>
        </li>
        
        
        <li class="menu-item ">
            <a href="/archives/" class="menu-item-link">Archives</a>
        </li>
        
        
        <li class="menu-item ">
            <a href="/atom.xml" class="menu-item-link">RSS</a>
        </li>
        
        
        <li class="menu-item ">
            <a target="_blank" rel="noopener" href="https://pixeltimer.art" class="menu-item-link">Pixel Timer</a>
        </li>
        
    </ul>
    <div class="search-box">
        <input type="search" id="search" placeholder="搜索">
    </div>
</header>
    <article class="post">
  <div class="post-meta">
    <span class="post-time">3 / 15, 2022</span>
  </div>
  <div class="post-title">
    <h1 class="title">通过 GitHub Actions 同步 Hexo 博客至 Gitee</h1>
  </div>
  
  <ul class="post-tags">
    
    <li class="tag-item">
      #折腾
    </li>
    
    <li class="tag-item">
      #github
    </li>
    
  </ul>
  
  <div class="post-content">
    <p><a href="https://evolly.one/p/26406.html">上一篇</a>我讲了通过 GitHub Actions 自动部署博客。GitHub 是国外的服务，国内对应的有 Gitee，Gitee 也提供了 Gitee Pages 服务，可以托管静态页面，不过 GItee 对内容有内容审查，没有 GitHub 那么开放。我这次折腾也顺便把博客同步到了 Gitee。</p>
<h2 id="创建账号"><a href="#创建账号" class="headerlink" title="创建账号"></a>创建账号</h2><p>首先创建注册 Gitee 账户就不细说了，注册好后顺便把微信公众号绑定好，不然后面部署的时候可能会导致失败。</p>
<h2 id="设置-Actions-secrets"><a href="#设置-Actions-secrets" class="headerlink" title="设置 Actions secrets"></a>设置 Actions secrets</h2><p>在<strong>私有仓库</strong>的 Actions secrets 中再添加两个 secret，在上一篇中我已经加了一个 secret，现在再加一个 Gitee 的登录密码跟 git 的本地私钥。</p>
<p>Gitee 的本地密码用处是后续需要脚本模拟人工操作，部署 Gitee Pages，因为 Gitee Pages 每次更新都需要手动点击部署按钮。</p>
<p>本地私钥的话是为了有权限往 Gitee 仓库推送代码。因为现在是两个不同的平台之间同步代码，所以需拉取 Github 上博客的公开仓库，然后推送到 Gitee 的目标仓库。正常情况下用过 Github，本地电脑应该已经生成了 KEY。</p>
<p>我使用的是 Mac，KEY 生成的目录默认是<code>~/.ssh</code>：</p>
<p><code>id_rsa</code> 是私钥，<code>id_ras.pub</code> 是公钥。</p>
<p><img src="https://personal-1251959693.cos.ap-chengdu.myqcloud.com/2022-03-15-024626.png"></p>
<p>通过 <code>cat ~/.ssh/id_rsa</code> 可以读取公&#x2F;私钥内容。</p>
<p>公钥需要添加到 Gitee 中：</p>
<p><img src="https://personal-1251959693.cos.ap-chengdu.myqcloud.com/2022-03-15-025028.png"></p>
<p>私钥添加到 GitHub 的博客私有仓库。</p>
<p><img src="https://personal-1251959693.cos.ap-chengdu.myqcloud.com/2022-03-15-025348.png"></p>
<p>接下来在 GItee 创建一个仓库，仓库名最好与账户同名。至于原因可以看<a target="_blank" rel="noopener" href="https://gitee.com/help/articles/4136#article-header1">这里</a>。</p>
<p><img src="https://personal-1251959693.cos.ap-chengdu.myqcloud.com/2022-03-15-025621.png"></p>
<p>创建好后我的是这样的：</p>
<p><img src="https://personal-1251959693.cos.ap-chengdu.myqcloud.com/2022-03-15-030122.png"></p>
<p>顺便把 Gitee Pages 服务开通：</p>
<p><img src="https://personal-1251959693.cos.ap-chengdu.myqcloud.com/2022-03-15-031650.png"></p>
<p>第一次我们需要手动点一下更新，否则后面脚本会执行失败。</p>
<p>接下来写配置：</p>
<pre><code class="yaml">name: gitee-deploy

on:
  push:
    branches: [main]
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Sync to Gitee
        uses: wearerequired/git-mirror-action@master
        env:
          # 注意在 Settings-&gt;Secrets 配置 GITEE_RSA_PRIVATE_KEY
          SSH_PRIVATE_KEY: $&#123;&#123; secrets.GITEE_RSA_PRIVATE_KEY &#125;&#125;
        with:
          # 注意替换为你的 GitHub 源仓库地址
          source-repo: git@github.com:Tit1e/evolly.github.io.git
          # 注意替换为你的 Gitee 目标仓库地址
          destination-repo: git@gitee.com:tit1e/tit1e.git

      - name: Build Gitee Pages
        uses: yanglbme/gitee-pages-action@main
        with:
          # 注意替换为你的 Gitee 用户名
          gitee-username: tit1e
          # 注意在 Settings-&gt;Secrets 配置 GITEE_PASSWORD
          gitee-password: $&#123;&#123; secrets.GITEE_PASSWORD &#125;&#125;
          # 注意替换为你的 Gitee 仓库，仓库名严格区分大小写，请准确填写，否则会出错
          gitee-repo: tit1e/tit1e
          # 要部署的分支，默认是 master，若是其他分支，则需要指定（指定的分支必须存在）
          branch: master
</code></pre>
<p>这是单独一个配置文件，我实际配置文件跟这个略有不同，因为我之前还有一个 Hexo 自动部署的脚本。</p>
<p>如果两个脚本分开写，那么在文章提交后，两个脚本同时执行，但博客自动部署脚本需要安装依赖，生成静态文件，这需要不少时间，而同步 Gitee 的脚本立马就可以执行，这会导致 Gitee 拉取到的代码永远是旧的，因此我把两个脚本合到一起，并规定了执行顺序，下面是我实际的使用脚本：</p>
<pre><code class="yaml">name: 部署 GitHub Pages 并同步至 Gitee Pages
on:
  push:
    branches:
      - main # master 分支有 push 行为时就触发这个 action

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@master

      - name: Build and Deploy
        # 使用专门部署 Hexo 到 GitHub pages 的 action
        uses: Tit1e/hexo-deploy-github-pages-action@master
        env:
          PERSONAL_TOKEN: $&#123;&#123; secrets.HEXO_DEPLOY &#125;&#125; # secret 名
          PUBLISH_REPOSITORY: Tit1e/evolly.github.io # 公共仓库，格式：GitHub 用户名/仓库名
          BRANCH: master # 分支，填 gh-pages 就行
          PUBLISH_DIR: ./public # 部署 public 目录下的文件
  async-gitee:
      # 需要 build-and-deploy 这个 job 执行完再执行当前脚本
    needs: build-and-deploy
    runs-on: ubuntu-latest
    steps:
      - name: Sync to Gitee
        uses: wearerequired/git-mirror-action@master
        env:
          # 注意在 Settings-&gt;Secrets 配置 GITEE_RSA_PRIVATE_KEY
          SSH_PRIVATE_KEY: $&#123;&#123; secrets.GITEE_RSA_PRIVATE_KEY &#125;&#125;
        with:
          # 注意替换为你的 GitHub 源仓库地址
          source-repo: git@github.com:Tit1e/evolly.github.io.git
          # 注意替换为你的 Gitee 目标仓库地址
          destination-repo: git@gitee.com:tit1e/tit1e.git

      - name: Build Gitee Pages
        uses: yanglbme/gitee-pages-action@main
        with:
          # 注意替换为你的 Gitee 用户名
          gitee-username: tit1e
          # 注意在 Settings-&gt;Secrets 配置 GITEE_PASSWORD
          gitee-password: $&#123;&#123; secrets.GITEE_PASSWORD &#125;&#125;
          # 注意替换为你的 Gitee 仓库，仓库名严格区分大小写，请准确填写，否则会出错
          gitee-repo: tit1e/tit1e
          # 要部署的分支，默认是 master，若是其他分支，则需要指定（指定的分支必须存在）
          branch: master
</code></pre>
<p>第二个 job 添加了<code>needs: build-and-deploy</code>这个配置。有了它，第二个脚本就会在第一个脚本执行之后才开始执行，这样就能保证拉到的博客是最新的。</p>
<p><strong>注意 Gitee 一定要绑定微信公众号。</strong></p>
<p>然后就提交博客源码可以看下执行结果，正常的话 Gitee 会收到登陆提醒。</p>
<p><img src="https://personal-1251959693.cos.ap-chengdu.myqcloud.com/2022-03-15-032443.png"></p>
<p>如果有报错，可以对照错误找<a target="_blank" rel="noopener" href="https://github.com/yanglbme/gitee-pages-action#%E9%94%99%E8%AF%AF%E5%8F%8A%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88">解决方案</a>。</p>

  </div>
  <div class="post-near">
    
    <a
      class="post-near-prev"
      href="/p/6650.html"
      title="斐讯 K2P 官改固件 AP 设置"
    >
      <span class="arrow">←</span>
      <span class="post-near-title">
        斐讯 K2P 官改固件 AP 设置
      </span>
    </a>
    
    
    <a
      class="post-near-next"
      href="/p/26406.html"
      title="使用 GitHub Actions 自动部署 Hexo 博客"
    >
      <span class="post-near-title">
        使用 GitHub Actions 自动部署 Hexo 博客
      </span>
      <span class="arrow">→</span>
    </a>
    
  </div>
</article>

    <footer class="footer">
  <p>本博客采用 <a class="license-link" rel="license noopener" target="_blank" href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh">署名-非商业性使用-相同方式共享 4.0 国际</a>协议进行许可</p>
  <p>
    <span>Thanks For <a target="_blank" rel="noopener" href="https://github.com/nanxiaobei/hugo-paper" taget="_blank">hugo-paper</a></span>
    <span style="margin-left: 10px;">&copy; 2016-2025 by Tit1e</span>
  </p>
</footer>
    </div>
    <script src="//unpkg.com/@highlightjs/cdn-assets@11.5.0/highlight.min.js"></script>
<script>
  hljs.initHighlightingOnLoad();
  var _hmt = _hmt || [];
    (function() {
    var hm = document.createElement("script");
    hm.src = "https://hm.baidu.com/hm.js?6349d3bc54baea0b04a65145c5e3b799";
    var s = document.getElementsByTagName("script")[0];
    s.parentNode.insertBefore(hm, s);
    })();
    const block = document.querySelectorAll('.post-content')[0]
    block.addEventListener('click', e => {
        const {nodeName, src} = e.target
        if(nodeName !== 'IMG') return
        document.body.classList.add('overflow-hidden')
        const div = document.createElement('div')
        div.id = 'global-cover'
        div.title = '点击关闭'
        const a = document.createElement('a')
        a.href = src
        a.target="_blank"
        a.title = '点击打开原图'
        const img = document.createElement('img')
        img.className = 'show-pic'
        img.src = src
        a.appendChild(img)
        div.appendChild(a)
        document.body.appendChild(div)
    })
    document.body.addEventListener('click', e => {
        if(e.target.id === 'global-cover'){
            document.body.classList.remove('overflow-hidden')
            document.body.removeChild(e.target)
        }
    })
</script>
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-7M04VN3JZ4"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());

  gtag('config', 'G-7M04VN3JZ4');
</script>

<script src="/js/search.js"></script>


</body>
</html>